local io = require[[async-io]]
local async = require[[async]].new()
local stream = require[[stream]]
local state = require[[state]]

local sign = function(x) return (x < 0 and -1 or 1) end

local is = function(x) return function(y) return y == x end end
local gt = function(x) return function(y) return y >  x end end
local always = function(x) return function() return x end end
local plus = function() return function(a, b) return a + b end end
local take_last = function() return function(x) return x[#x] end end
local count = function() return function(x) return #x end end
local signed_sqr = function() return function(x) return x*x*sign(x) end end
local even = function() return function(x) return x % 2 == 0 end end
local prefix_print = function(prefix) return function(x) print(prefix .. x) end end
local prefix_print2 = function(prefix) return function(t, x) print(prefix .. x, "@" .. t) end end
local zero_unless2 = function(f) return function(a, b) return b and f(a, b) or 0 end
end

io.install_default(async)

local button = stream.from_button_press()
local btn_a = button:filter(is('a')):map(always(1))
local btn_d = button:filter(is('d')):map(always(-1))
local btn_s = button:filter(is('s')):map(always(nil))

local pos = stream.merge(btn_a, btn_d, btn_s):scan(zero_unless2(plus()), 0)
local sspos = pos:map(signed_sqr())
local sepos = sspos:filter(even())
local ssspos = sspos:state(0)
local ssepos = sepos:state(0)
ssspos.on_change(prefix_print[[> ]])
ssepos.on_change(prefix_print[[= ]])
ssepos:sample(0.5).on_event(prefix_print2"sample\t")

local btn_q_count = button:filter(is('q')):throttle(0.3):map(count())
local q_single = btn_q_count:filter(is(1)):map(always("double hit q to exit"))
local q_double = btn_q_count:filter(is(2)).on_event(function() async:quit() end)
local q_more = btn_q_count:filter(gt(2)):map(function(x) return ("awesome %d hit"):format(x) end)
local q_text = q_single:merge(q_more):state("ready")
q_text.on_change(function(x) print(x) end)

async:run()

